<?php
  define('EPOCH', 1165775387);

  // fetches data from klab.lv, 
  // returns string array containing friends for this nick
  function get_sc_userinfo_html($id) {
    $nick = get_user_nick($id);
    return file_get_contents('http://klab.lv/userinfo.bml?user='.$nick);
  }

  function get_sc_friends($data) {

    $start = strpos($data, "friends'>Draugi</a>:</b>");
    $data = substr($data, $start);
    $finish = strpos($data, "Esmu draugs:</b></td>");
    $data = substr($data, 0, $finish);
    $finish = strpos($data, "<img src='http://klab.lv/img/community.gif'");
    if ($finish) {
      $data = substr($data, 0, $finish);
    }
    
    #<a href='/userinfo.bml?user=alive'>alive</a>
    $pattern = "/<a href='\/userinfo\.bml\?user=(\w+)'>/";
    preg_match_all($pattern, $data, $matches);
    
    if (!isset($matches[1])) 
      return array();
    
    return $matches[1];
  }  

  // nick -> id
  function get_user_id($nick) {
    $q = "select id from sc_users where nick = '$nick'";
    $res = fetchone($q);
    
    if (!$res) { 
      // wow new user?
      $iq = "insert into sc_users (nick) values ('$nick')";
      query($iq);
      
      $res = fetchone($q);
    }
    
    return $res['id'];
  }

  function get_user_id_dumb($nick) {
    $q = "select id from sc_users where nick = '$nick'";
    $res = fetchone($q);
    if (!$res) return '';
    return $res['id'];
  }


  // nick -> id  
  function get_user_nick($id) {
    $q = "select nick from sc_users where id = $id";
    $res = fetchone($q);
    return $res['nick'];
  }
  
  // [o[nick], o[nick]] -> [nick, nick]
  function get_nick($o) {
    return $o['nick'];
  }
  
  // returns string of current db friend nicks for a given user
  function get_db_friends($id) {
    
    $q = "select distinct nick from sc_friendships f "
       . " left join sc_users u on f.friendee_id = u.id " 
       . " where finish is null "
       . " and friender_id = $id ";
       
    return array_map("get_nick", fetchall($q));
  }


  // [a, b, c] -> [a=>1, b=>1, c=>1]
  function list_to_dict($l) {
    $res = array();
    foreach($l as $s)
      $res[$s] = 1;
      
    return $res;
  }

  function update_friendships($id, $db, $sc) {
    $db_dict = list_to_dict($db);
    $sc_dict = list_to_dict($sc);
    
    if (!$sc) return true; // no, empty sc won't do!
    
    foreach ($db as $db_friend)
      if (!array_key_exists($db_friend, $sc_dict))
        register_friendship_end($id, get_user_id($db_friend));

    foreach ($sc as $sc_friend)
      if (!array_key_exists($sc_friend, $db_dict))
        register_friendship_start($id, get_user_id($sc_friend));

  }
  
  function register_friendship_start($friender, $friendee) {
    if ($friender == $friendee) return;
    
    $now = time();
    $q = "insert into sc_friendships (friender_id, friendee_id, start) "
       . " values ($friender, $friendee, $now)";
       
    query($q);
  }

  function register_friendship_end($friender, $friendee) {
    if ($friender == $friendee) return;
    
    $now = time();
    
    $q = "update sc_friendships set finish = $now "
       . " where friender_id = $friender and friendee_id = $friendee "
       . " and finish is null ";
       
    query($q);
  }

  function update_deletion($id, $data) {
    # have we registered deletion already?
    $q = "select count(*) as cnt from sc_deletions "
       . " where user_id = $id and finish is null ";

    $obj = fetchone($q);   
    $have_deletion = $obj['cnt'];

    if (strpos($data, "<title>Sviesta Ciba | Es izdzēsos!</title>")) {
      $is_deleted = 1;
      if (!$have_deletion) {
        # register... 
        $now = time();
        $q = "insert into sc_deletions (user_id, start) "
           . " values ($id, $now) ";
        execute($q);
      }        
    } else {
      $is_deleted = 0;
      if ($have_deletion) {
        # mark it as finished
        $now = time();
        $q = "update sc_deletions set finish = $now "
           . " where user_id = $id ";
        execute($q);
      }
    }
    return $is_deleted;
  }
  
  function update_some() {
    // find out the least updated ones
    for ($i = 0; $i < 10; $i++) {
      # take the oldest.
      # requery in each iteration because there can actually be several
      # updates inside update_one
      $q = "select id from sc_users "
         . " order by last_update asc "
         . " limit 1 ";

      $id_obj = fetchone($q);
      $id = $id_obj['id'];
      update_one($id);
    }
  }
  
  function update_one($id) {
    $data = get_sc_userinfo_html($id);
    $is_deleted = update_deletion($id, $data);

    if (!$is_deleted) {
      $sc_friends = get_sc_friends($data);
      $db_friends = get_db_friends($id);
      update_friendships($id, $db_friends, $sc_friends);
    }

    $now = time();
    $q = "update sc_users set last_update = $now where id = $id";
    query($q);
  }

  function get_avg_age() {
    $q = "select avg(coalesce(last_update, 0)) as avg_age from sc_users";
    $res = fetchone($q);
    if (!$res) return 0; // wt...
    return $res['avg_age'];
  }

  // average data age
  // requests in last 10 minutes  
  // nosacījumi: data age nevajag mazāku par vienu dienu
  //             requests in last 10 minutes nedrīkst pārsniegt 60 (piemēram)
  function work() {
    while (1 == 1) {
      // avg age
      $dayago = time() - 40000;
      $avg_age = get_avg_age();
      if (!$avg_age) return 0; // wt...
      if ($avg_age > $dayago) return 1;
      
      // request limit
      $ten_min_ago = time() - 600;
      $q = "select count(*) as count from sc_users where last_update > $ten_min_ago";
      $res = fetchone($q);
      if (!$res) return 0; // wt...
      if ($res['count'] > 200) return 2;
      
      update_some(); // updates 10 users, then repeats checks
    }    
  }
  
  // initiates worker, gathers stats
  function initiate_work() {
    $end_condition = work();
    $avg_age = get_avg_age();
    $now = time();

    $q = "insert into sc_log (timestamp, end_condition, avg_age) "    
       . " values ($now, $end_condition, $avg_age) ";
       
    query($q);
  }


  function glue_lists($starts, $finishes) {
    $stamps = array();
    $i = 0;
    foreach ($starts as $start) {
      $i += 1;
      $start['action'] = 'start';
      $start['time'] = $start['start'];
      $stamps[$start['time'].'.'.$i] = $start;
    }
      
    foreach ($finishes as $finish) {
      $i += 1;
      $finish['action'] = 'finish';
      $finish['time'] = $finish['finish'];
      $stamps[$finish['time'].'.'.$i] = $finish;
    }
    
    
    krsort($stamps);
    
    return array_values($stamps);
  }

  function stats($nick) {
    $id = get_user_id_dumb($nick);
    if (!$id) return;
    
    // register request
    $now = time();
    $q = "select count(*) as count from sc_requests where nick = '$nick'";
    $c = fetchone($q);
    if ($c['count'] == 0)
      $q = "insert into sc_requests values ('$nick', $now)";
    else 
      $q = "update sc_requests set time = $now where nick = '$nick'";

    
    query($q);  
    
    
    
    // update_one($id);
    
    $q = "select start, nick from sc_friendships f "
       . " left join sc_users u on f.friender_id = u.id "
       . " where f.friendee_id = $id and start >  ".EPOCH
       . " order by start desc "
       . " limit 50 ";
       
    $starts = fetchall($q);
    
    $q = "select finish, nick from sc_friendships f "
       . " left join sc_users u on f.friender_id = u.id "
       . " where f.friendee_id = $id "
       . " and finish is not null and finish > ".EPOCH
       . " order by finish desc "
       . " limit 50 ";
       
    $finishes = fetchall($q);
    
    return glue_lists($starts, $finishes);
    
  }
  
  function global_stats() {
    $q = "select start, u1.nick as friendee_nick, u2.nick as friender_nick "
       . " from sc_friendships f "
       . " left join sc_users u1 on f.friendee_id = u1.id "
       . " left join sc_users u2 on f.friender_id = u2.id "
       . " where start >  ".EPOCH
       . " order by start desc "
       . " limit 50 ";
       
    $starts = fetchall($q);
    
    $q = "select finish, u1.nick as friendee_nick, u2.nick as friender_nick "
       . " from sc_friendships f "
       . " left join sc_users u1 on f.friendee_id = u1.id "
       . " left join sc_users u2 on f.friender_id = u2.id "
       . " where finish is not null "
       . " and finish >  ".EPOCH
       . " order by finish desc "
       . " limit 50 ";
       
    $finishes = fetchall($q);
    
    return glue_lists($starts, $finishes);    
  }

  // initiates worker, gathers stats
  function initiate_single_batch() {
    for ($i = 0; $i < 20; $i++) {
      update_some();
      sleep(0.3);
    }
    
    $end_condition = 3;
    $avg_age = get_avg_age();
    $now = time();

    $q = "insert into sc_log (timestamp, end_condition, avg_age) "    
       . " values ($now, $end_condition, $avg_age) ";
       
    query($q);
  }

?>
